// compile: g++ -o test_time test_time.cc -std=c++11
// run: ./test_time
// RAII用法，测试函数用时
#include <chrono>
#include <iostream>
#include <string>
#include <thread>
using namespace std::chrono;
class TimerCal {
 public:
  TimerCal(const std::string& tag) : tag_(tag) {
    begin_ = high_resolution_clock::now();
  }
  ~TimerCal() {
    auto time =
        duration_cast<milliseconds>(high_resolution_clock::now() - begin_)
            .count();
    std::cout << "time { " << tag_ << " } " << static_cast<double>(time)
              << " ms" << std::endl;
  }
  unsigned long long ElapsedMs() {
    return duration_cast<milliseconds>(high_resolution_clock::now() - begin_)
        .count();
  }
  void Reset() { begin_ = high_resolution_clock::now(); }

  static std::chrono::time_point<std::chrono::high_resolution_clock> Now() {
    return std::chrono::high_resolution_clock::now();
  }
  static unsigned long long DiffUs(
      std::chrono::time_point<std::chrono::high_resolution_clock> before,
      std::chrono::time_point<std::chrono::high_resolution_clock> after) {
    return static_cast<unsigned long long>(
        duration_cast<std::chrono::microseconds>(after - before).count());
  }
  static unsigned long long DiffMs(
      std::chrono::time_point<std::chrono::high_resolution_clock> before,
      std::chrono::time_point<std::chrono::high_resolution_clock> after) {
    return static_cast<unsigned long long>(
        duration_cast<std::chrono::milliseconds>(after - before).count());
  }
  static unsigned long long DiffS(
      std::chrono::time_point<std::chrono::high_resolution_clock> before,
      std::chrono::time_point<std::chrono::high_resolution_clock> after) {
    return static_cast<unsigned long long>(
        duration_cast<std::chrono::seconds>(after - before).count());
  }

 private:
  time_point<high_resolution_clock> begin_;
  std::string tag_;
};

// #define CAL_SCOPE_TIME(str) TimerCal(str) // bug，不能使用临时对象
#define CAL_SCOPE_TIME(str) TimerCal t(str)
#define CAL_TIME_BEG(str) auto begin_##str = TimerCal::Now()
#define CAL_TIME_END(str)                                              \
  std::cout << "time { " << #str << " } "                              \
            << TimerCal::DiffMs(begin_##str, TimerCal::Now()) << "ms " \
            << std::endl;

void Test1() {
  CAL_SCOPE_TIME("TEST1");
  CAL_TIME_BEG(1);
  std::this_thread::sleep_for(std::chrono::seconds(1));
  CAL_TIME_END(1);
  CAL_TIME_BEG(2);
  std::this_thread::sleep_for(std::chrono::seconds(2));
  CAL_TIME_END(2);
  CAL_TIME_BEG(3);
  std::this_thread::sleep_for(std::chrono::seconds(3));
  CAL_TIME_END(3);
}
int main() {
  Test1();
  return 0;
}